/*
 * fml_adc.c
 *
 *  Created on: 2025年4月7日
 *      Author: 22332
 */
#include <stdio.h>
#include "cola_init.h"
#include "cola_os.h"
#include "cola_device.h"
#include "fml_adc.h"
#include "fml_public.h"
#include "fml_Pwm.h"
#include "shell.h"

typedef enum BSP_ADC_OPS_TYPE
{
	EN_ADC_OPS_BOARD_NTC = 1,   				//读取主板温度
    EN_ADC_OPS_TYPE_BAT,  	   					//读取B+电压
    EN_ADC_OPS_TFT_NTC,       					//读取屏背光NTC温度值
} EN_ADC_OPS_TYPE;

//#define SUPPORT_NTC_DEBUG						//打开支持TFT NTC温度AD采集使用用shell输入值

#if 0
//小数
#define BAT_Rp      			37.4            //上拉电阻37.4K
#define BAT_R1      			4.7             //分压电阻4.7k
#define BAT_LOSS				0.5				//二极管损耗0.5v

#define ADC_VREF				(3.3)			//ADC参考电压3.3v
#define ADC_ACCURACY 			(1UL << 12U)	//12位采样ADC
#define ADC_CAL_VOL(adcVal) 	(float)(((float)(adcVal) * ADC_VREF) / ((float)ADC_ACCURACY))//ADC采集到的电压值

#define BAT_RATIO   			(((float)BAT_R1+(float)BAT_Rp)/(float)BAT_R1) 		//按电阻比例进行分压
#define BAT_GET(adcVal)    		((BAT_RATIO*(float)ADC_CAL_VOL(adcVal))+BAT_LOSS)	//计算板子这端的B+电压
#else
//整数
#define BAT_Rp      			374             //上拉电阻37.4K
#define BAT_R1      			47              //分压电阻4.7k
#define BAT_LOSS				(500+400)		//二极管损耗0.5v

#define ADC_VREF				(3300)			//ADC参考电压3.3v
#define ADC_ACCURACY 			(1UL << 12U)	//12位采样ADC
#define ADC_CAL_VOL(adcVal) 	adcVal * ADC_VREF / ADC_ACCURACY//ADC采集到的电压值

#define BAT_RATIO   			(BAT_R1+BAT_Rp)/BAT_R1			//按电阻比例进行分压
#define BAT_GET(adcVal)    		((BAT_R1+BAT_Rp)*(adcVal * ADC_VREF)/(BAT_R1*ADC_ACCURACY)+BAT_LOSS)//计算板子这端的B+电压
#endif

#define ADC_SAMPLE_CNT			10

static cola_device_t *g_pDevadc = NULL;
static uint16_t g_iTftNTCAd=2617;						//30°C[L0],PWM=255*100%=255
//static uint16_t g_iTftNTCAd=1291;						//71°C[L1],PWM=255*90%=229
//static uint16_t g_iTftNTCAd=1190;						//75°C[L2],PWM=255*80%=204
//static uint16_t g_iTftNTCAd=1096;						//79°C[L3],PWM=255*70%=178
//static uint16_t g_iTftNTCAd=1008;						//83°C[L4],PWM=255*60%=153
//static uint16_t g_iTftNTCAd=927;						//87°C[L5],PWM=255*50%=127
static bool g_bEnPrintNTC = false;						//使能打印NTC温度数据
static int g_tempRestore;								//温度上升后,下一步温度下降时的恢复值
static int g_iTempLevel = 0;							//当前温度等级
static int g_iTempLevel_old = 0;						//之前温度等级
static int g_iCntDlyg;									//温度等级发生变化后的持续时间
static int g_iOldIndex = -1;							//记录上一次的温度等级
static int g_iOldPwm = 0,g_iNewPwm = 0;					//记录上一次和当前的PWM设定值
static bool g_bEnPwmAutoChange = false;					//使能PWM变化
static uint16_t g_pAdcTempArray[ADC_SAMPLE_CNT]={0};	//温度AD采集BUF

static int g_pNtcADC[] =
{
	4000,	//-40
	3994,	//-39
	3989,	//-38
	3983,	//-37
	3977,	//-36
	3970,	//-35
	3963,	//-34
	3956,	//-33
	3949,	//-32
	3941,	//-31
	3933,	//-30
	3925,	//-29
	3916,	//-28
	3907,	//-27
	3897,	//-26
	3887,	//-25
	3877,	//-24
	3866,	//-23
	3855,	//-22
	3844,	//-21
	3832,	//-20
	3820,	//-19
	3807,	//-18
	3794,	//-17
	3780,	//-16
	3766,	//-15
	3751,	//-14
	3736,	//-13
	3721,	//-12
	3705,	//-11
	3688,	//-10
	3671,	//-9
	3653,	//-8
	3635,	//-7
	3616,	//-6
	3597,	//-5
	3577,	//-4
	3557,	//-3
	3536,	//-2
	3515,	//-1
	3493,	//0
	3470,	//1
	3448,	//2
	3424,	//3
	3400,	//4
	3376,	//5
	3350,	//6
	3325,	//7
	3299,	//8
	3272,	//9
	3245,	//10
	3218,	//11
	3189,	//12
	3161,	//13
	3132,	//14
	3102,	//15
	3072,	//16
	3042,	//17
	3011,	//18
	2980,	//19
	2949,	//20
	2917,	//21
	2885,	//22
	2852,	//23
	2820,	//24
	2786,	//25
	2753,	//26
	2719,	//27
	2685,	//28
	2651,	//29
	2617,	//30
	2582,	//31
	2548,	//32
	2513,	//33
	2478,	//34
	2443,	//35
	2408,	//36
	2373,	//37
	2338,	//38
	2303,	//39
	2268,	//40
	2233,	//41
	2198,	//42
	2164,	//43
	2129,	//44
	2094,	//45
	2060,	//46
	2025,	//47
	1991,	//48
	1957,	//49
	1923,	//50
	1890,	//51
	1857,	//52
	1824,	//53
	1791,	//54
	1758,	//55
	1726,	//56
	1694,	//57
	1663,	//58
	1631,	//59
	1600,	//60
	1570,	//61
	1541,	//62
	1511,	//63
	1482,	//64
	1454,	//65
	1426,	//66
	1398,	//67
	1371,	//68
	1344,	//69
	1317,	//70
	1291,	//71
	1265,	//72
	1240,	//73
	1215,	//74
	1190,	//75
	1166,	//76
	1142,	//77
	1119,	//78
	1096,	//79
	1073,	//80
	1051,	//81
	1029,	//82
	1008,	//83
	987,	//84
	967,	//85
	947,	//86
	927,	//87
	908,	//88
	889,	//89
	870,	//90
	852,	//91
	834,	//92
	816,	//93
	799,	//94
	782,	//95
	766,	//96
	750,	//97
	734,	//98
	718,	//99
	703,	//100
	688,	//101
	674,	//102
	660,	//103
	646,	//104
	632,	//105
	619,	//106
	606,	//107
	593,	//108
	581,	//109
	569,	//110
	557,	//111
	545,	//112
	534,	//113
	523,	//114
	512,	//115
	501,	//116
	491,	//117
	481,	//118
	471,	//119
	461,	//120
	452,	//121
	442,	//122
	433,	//123
	425,	//124
	416,	//125
	407,	//126
	399,	//127
	391,	//128
	383,	//129
	375,	//130
	368,	//131
	360,	//132
	353,	//133
	346,	//134
	339,	//135
	332,	//136
	326,	//137
	319,	//138
	313,	//139
	307,	//140
	301,	//141
	295,	//142
	289,	//143
	284,	//144
	278,	//145
	273,	//146
	267,	//147
	262,	//148
	257,	//149
	252 	//150
};

/*FUNCTION**********************************************************************
 *
 * Function Name : sort
 * Description   : 将数组从小到大进行排序
 *
 *END**************************************************************************/
static void sort(uint16_t *pBuf,int len)
{
	uint16_t temp;
	uint8_t i,j;
	for(i=0; i<len-1; i++)
	{
		for(j=i+1; j<len; j++)
		{
			if(pBuf[i]>pBuf[j])
			{
				temp = pBuf[i];
				pBuf[i] = pBuf[j];
				pBuf[j] = temp;
			}
		}
	}
}

/*FUNCTION**********************************************************************
 *
 * Function Name : fml_adc_filter
 * Description   : 将数组进行排序后,去掉一个最大和最小值,将剩下的值做平均
 *
 *END**************************************************************************/
uint16_t fml_adc_filter(uint16_t *buf,int len)
{
	int sum = 0;
	sort(buf,len);
	for(int i=1; i<(len-1); i++)
		sum+= buf[i];
	sum = sum/(len-2);
	//sum = buf[len/2];
	return sum;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : fml_adc_to_bat_voltage
 * Description   : 将采集的ADC值,根据电阻分压求出B+的电压值
 *
 *END**************************************************************************/
uint16_t fml_adc_to_bat_voltage(uint16_t adc)
{
	return BAT_GET(adc);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : fml_adc_read_bat_ad
 * Description   : 读BAT检测AD值
 *
 *END**************************************************************************/
uint16_t fml_adc_read_bat_ad(void)
{
	uint16_t iBattAd = cola_device_read(g_pDevadc,EN_ADC_OPS_TYPE_BAT,0,0);
	return iBattAd;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : fml_adc_read_tft_ntc_ad
 * Description   : 读屏背光NTC检测AD值
 *
 *END**************************************************************************/
uint16_t fml_adc_read_tft_ntc_ad(void)
{
#ifdef SUPPORT_NTC_DEBUG
	return g_iTftNTCAd;
#else
	uint16_t adValue = cola_device_read(g_pDevadc,EN_ADC_OPS_TFT_NTC,0,0);
	g_iTftNTCAd = adValue;
	return adValue;

#endif
}

/*FUNCTION**********************************************************************
 *
 * Function Name : fml_adc_read_board_ntc_ad
 * Description   : 读主板NTC检测AD值
 *
 *END**************************************************************************/
uint16_t fml_adc_read_board_ntc_ad(void)
{
	uint16_t adValue = cola_device_read(g_pDevadc,EN_ADC_OPS_BOARD_NTC,0,0);
	return adValue;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : fml_adc_init
 * Description   : 初始化ADC采集任务
 *
 *END**************************************************************************/
void fml_adc_init(void)
{
	g_pDevadc = cola_device_find("DEVICE_ADC");
    if(g_pDevadc)
    	cola_device_open(g_pDevadc, 0);
}


/*FUNCTION**********************************************************************
 *
 * Function Name : fml_get_tft_ntc_adc
 * Description   : 读屏背光NTC检测AD值
 *
 *END**************************************************************************/
uint16_t fml_get_tft_ntc_adc(void)
{
	return g_iTftNTCAd;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : fml_set_tft_ntc_adc
 * Description   : 设置屏背光NTC检测AD值
 *
 *END**************************************************************************/
void fml_set_tft_ntc_adc(uint16_t value)
{
	g_iTftNTCAd = value;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : fml_adc_tft_ntc_temp_process
 * Description   : 将TFT NTC的温度转换成对应的PWM值
 *
 *END**************************************************************************/
static void fml_adc_tft_ntc_temp_process(int ntcTemp)
{
	static bool bTempRiseUp = false;
	static const uint8_t LCD_PWM_DUTY[] = {255,255*9/10, 255*8/10, 255*7/10, 255*6/10,255*5/10}; // 温度等级对应的PWM值
	enum
	{
		TEMP_HYSTERESIS = 4,// 温度迟滞值(℃)
		DEBOUNCE_DELAY= 10 // 消抖延迟周期数
	};
	/* 温度等级计算（优化为区间判断） */
	g_iTempLevel = (ntcTemp > 86) ? 5 :
	(ntcTemp > 82) ? 4 :
	(ntcTemp > 78) ? 3 :
	(ntcTemp > 74) ? 2 :
	(ntcTemp > 70) ? 1 : 0;

	/* 温度等级变化处理（带迟滞检测） */
	if (g_iTempLevel != g_iTempLevel_old)
	{
		g_iOldIndex = g_iTempLevel_old;
		if(g_iTempLevel>=g_iTempLevel_old)
		{
			// 温度上升：设置恢复点（当前温度-迟滞值）
			g_tempRestore = ntcTemp - TEMP_HYSTERESIS;
			logWrite("1.ntcTemp=%d,set g_tempRestore=%d,g_iTempLevel=%d\r\n",ntcTemp,g_tempRestore,g_iTempLevel);
			bTempRiseUp = true;
		}
		else
		{
			// 温度下降：检查是否达到恢复点
			if (ntcTemp > g_tempRestore)
			{
				logWrite("2. Temperature drop delayed: ntcTemp:%d > g_tempRestore:%d,g_iTempLevel=%d\r\n",ntcTemp, g_tempRestore,g_iTempLevel);
				return; // 未达恢复点，终止处理
			}
			g_tempRestore = ntcTemp - TEMP_HYSTERESIS;
			bTempRiseUp = false;
		}

		// 更新等级状态并启动消抖计数器
		g_iTempLevel_old = g_iTempLevel;
		logWrite("3.ntcTemp=%d,g_tempRestore=%d,g_iTempLevel=%d\r\n",ntcTemp,g_tempRestore,g_iTempLevel);
		g_iCntDlyg = DEBOUNCE_DELAY;
	}

		/* 消抖计数器处理 */
	if (g_iCntDlyg > 0 && --g_iCntDlyg == 0)
	{
		g_iNewPwm  = LCD_PWM_DUTY[g_iTempLevel];
		g_iOldPwm  = fml_get_bsp_pwm_value();
		if (g_iOldPwm > g_iNewPwm)
		{
			if(bTempRiseUp)
			{
				g_bEnPwmAutoChange = true;
				logWrite("rise:g_iOldPwm=%d,g_iNewPwm=%d,bTempRiseUp=%d\r\n",g_iOldPwm,g_iNewPwm,bTempRiseUp);
			}
		}
		else
		{
			if(bTempRiseUp == false)
			{
				int max  = fml_get_host_pwm_value();
				if(g_iNewPwm > max)
					g_iNewPwm = max;
				g_bEnPwmAutoChange = true;
				logWrite("fall:g_iOldPwm=%d,g_iNewPwm=%d,bTempRiseUp=%d\r\n",g_iOldPwm,g_iNewPwm,bTempRiseUp);
			}
		}
	}
}

/*FUNCTION**********************************************************************
 *
 * Function Name : fml_adc_pwm_auto_change
 * Description   : 自动设置pwm值,使之不会突变
 *
 *END**************************************************************************/
void fml_adc_pwm_auto_change(void)
{
	if(g_bEnPwmAutoChange)
	{
		if(g_iOldPwm != g_iNewPwm)
		{
			if(g_iOldPwm > g_iNewPwm)
			{
				g_iOldPwm--;
			}
			else
			{
				g_iOldPwm++;
			}
			logWrite("Not Equal:g_iOldPwm=%d,g_iNewPwm=%d\r\n",g_iOldPwm,g_iNewPwm);
		}
		else
		{
			g_bEnPwmAutoChange = false;
			logWrite("Equal: g_iOldPwm=%d,g_iNewPwm=%d\r\n",g_iOldPwm,g_iNewPwm);
		}
		fml_pwm_change_duty(g_iOldPwm);
	}
}

/*FUNCTION**********************************************************************
 *
 * Function Name : fml_adc_convert_to_temperature
 * Description   : 将ntc adc值转换成实际的环境温度值
 *
 *END**************************************************************************/
int fml_adc_convert_to_temperature(int adc)
{
	int size = sizeof(g_pNtcADC) / sizeof(g_pNtcADC[0]);
	int min_diff = 0x7FFFFFFF; // 初始化为最大整数值
	int index = 0;

	for (int i = 0; i < size; i++)
	{
		// 计算当前ADC值与数组元素的绝对差值
		int diff = (g_pNtcADC[i] > adc) ? (g_pNtcADC[i] - adc) : (adc - g_pNtcADC[i]);
		// 如果找到更小的差值，更新索引和最小差值
		if (diff < min_diff)
		{
			min_diff = diff;
			index = i;
		}
	}
	return index-40;
}

void printArray(uint16_t *buf,int len)
{
	logWrite("TFT Array:");
	for(int i=0; i<len; i++)
	{
		logWrite("%d ",buf[i]);
	}
	logWrite("\r\n");
}

/*FUNCTION**********************************************************************
 *
 * Function Name : fml_ntc_temperature_process
 * Description   : 根据NTC温度值来设置TFT PWM值
 *
 *END**************************************************************************/
void fml_ntc_temperature_process(void)
{
	static int i = 0;
	g_pAdcTempArray[i++] = fml_adc_read_tft_ntc_ad();
	if(i==ADC_SAMPLE_CNT)
	{
		int tftTemp,boardTemp;
		uint16_t iTftNtcAdc,iBoardNtcAdc;
		i = 0;
		iTftNtcAdc	= fml_adc_filter(g_pAdcTempArray,ADC_SAMPLE_CNT);
		tftTemp = fml_adc_convert_to_temperature(iTftNtcAdc);

		iBoardNtcAdc= fml_adc_read_board_ntc_ad();
		boardTemp = fml_adc_convert_to_temperature(iBoardNtcAdc);

		if(g_bEnPrintNTC)
		{
			logWrite("iTftNtcAdc=%d,tftTemp:%d,iBoardNtcAdc=%d,boardTemp:%d,g_tempRestore=%d,", iTftNtcAdc,tftTemp,iBoardNtcAdc,boardTemp,g_tempRestore);
			printArray(g_pAdcTempArray,ADC_SAMPLE_CNT);
		}
		fml_adc_tft_ntc_temp_process(tftTemp);
	}
	fml_adc_pwm_auto_change();
}

/*FUNCTION**********************************************************************
 *
 * Function Name : fml_adc_set_pwm_change_stop
 * Description   : 停止pwm设置变化
 *
 *END**************************************************************************/
void fml_adc_set_pwm_change_stop(int value)
{
	g_bEnPwmAutoChange = false;
	g_iOldPwm = g_iNewPwm = value;
}

#ifdef SUPPORT_NTC_DEBUG
#include <stdlib.h>
int fml_adc(int argc, char *argv[])
{
	if (argc < 3) {
		logWrite("para length must greater than 3\r\n");
		return 0;
	}

	int mode = atoi(argv[1]);
	int value = atoi(argv[2]);
	if(mode == 0)
	{
		fml_set_tft_ntc_adc(value);
	}
	else if(mode == 1)
	{
		g_bEnPrintNTC = value?true:false;
	}
	return 0;
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), fml_adc, fml_adc, fml_adc,fml_adc);
#endif
